package com.glasses.manage.export.excel;

import com.glasses.manage.export.DataExportor;
import com.glasses.manage.export.DataField;
import com.glasses.manage.export.DataPage;
import com.glasses.manage.export.ExportDataSource;
import com.glasses.manage.export.csv.CsvDataExportor;
import jxl.Range;
import jxl.Workbook;
import jxl.format.UnderlineStyle;
import jxl.write.*;
import jxl.write.Number;
import jxl.write.biff.RowsExceededException;

import java.io.IOException;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Collection;
import java.util.Date;
import java.util.List;


/**
 * 描述: Excel数据导出工具,默认为CSV格式,CSV格式文件可以用excel正常打开(兼容03和07+) 如果指定为Excel,则导出Excel03
 *
 * @author yy
 */
public class ExcelExportor<T> extends DataExportor<T> {
    private MODE mode;

    private String sheetName;


    public ExcelExportor(List<DataField> fields, ExportDataSource<T> dataSource, OutputStream os) {
        this(fields, dataSource, os, MODE.CSV);
    }

    /**
     * 没有分页参数调用
     *
     * @param fields
     * @param dataSource
     * @param os
     * @param mode
     */
    public ExcelExportor(List<DataField> fields, ExportDataSource<T> dataSource, OutputStream os, MODE mode) {
        super(null, fields, dataSource, os);
        this.mode = mode;
    }

    /**
     * 带分页参数
     *
     * @param pageParam
     * @param fields
     * @param dataSource
     * @param os
     * @param mode
     */
    public ExcelExportor(DataPage pageParam, List<DataField> fields, ExportDataSource<T> dataSource, OutputStream os, MODE mode) {
        super(pageParam, fields, dataSource, os);
        this.mode = mode;
    }

    @Override
    public void export() throws IOException {
        if (mode == null || mode == MODE.CSV) {
            new CsvDataExportor<T>(fields, dataSource, os).export();
        } else {
            try {
                exportExcel07();
            } catch (RowsExceededException e) {
                throw new RuntimeException(e);
            } catch (WriteException e) {
                throw new RuntimeException(e);
            }
        }
    }


    private void exportExcel07() throws IOException, WriteException {
        Collection<?> dataList;
        WritableWorkbook workBook = Workbook.createWorkbook(os);
        WritableSheet sheet = workBook.createSheet(createSheetName(1), 0);
        int rowIndex = createHead(sheet);// 创建头部,并返回当前头部所占的行数.
        Object value;
        do {
            dataList = dataSource.getData();
            for (Object data : dataList) {
                for (int i = 0; i < fields.size(); i++) {
                    int colIndex = fields.get(i).currentCol;
                    if (fields.get(i).getField() == null || fields.get(i).getField().trim().equals("")) {
                        continue;
                    }
                    value = getValue(data, fields.get(i).getField());
                    if (value != null) {
                        WritableCell label = new Label(colIndex, rowIndex, value.toString());
                        if (value instanceof Date) {
                            String datePattern = fields.get(i).getDatePattern();
                            if (datePattern != null) {
                                SimpleDateFormat sdf = new SimpleDateFormat(datePattern);
                                label = new Label(colIndex, rowIndex, sdf.format(value));
                            }
                        } else if (fields.get(i).isNumber()) {
                            label = new Number(colIndex, rowIndex, Double.parseDouble(value.toString()));
                        }
                        if (fields.get(i).getDatePattern() != null) {
                            label = new Label(colIndex, rowIndex, value.toString() + fields.get(i).getDatePattern());
                        }
                        sheet.setColumnView(colIndex, fields.get(i).getColumnWidth());
                        sheet.mergeCells(colIndex, rowIndex, colIndex + fields.get(i).getColspan() - 1, rowIndex);
                        sheet.addCell(label);
                        colIndex = colIndex + fields.get(i).getColspan(); //下一次列开始的地方
                    }
                }
                rowIndex++;
            }
        } while (rowIndex <= dataList.size());
        workBook.write();
        workBook.close();
        os.flush();
    }

    /**
     * 将指定行创建为表头
     *
     * @param sheet
     * @throws WriteException
     * @throws RowsExceededException
     */
    private int createHead(WritableSheet sheet) throws WriteException {
        //一共单元格的个数
        int countArea = 0;
        //一共的行数（最大的行数）
        int maxRow = 0;
        for (DataField dataFiled : fields) {
            countArea += dataFiled.getColspan() * dataFiled.getRowspan();
            maxRow = (maxRow >= dataFiled.getCurrentNumber() + dataFiled.getRowspan()) ? maxRow : dataFiled.getCurrentNumber() + dataFiled.getRowspan();
        }
        //得到最大的列数
        int maxCol = countArea / maxRow;

        int rowIndex = 0;
        int colIndex = 0;
        for (DataField dataFiled : fields) {
            //字体
            WritableFont font = new WritableFont(WritableFont.createFont("宋体"), 10, WritableFont.BOLD, false, UnderlineStyle.NO_UNDERLINE, jxl.format.Colour.WHITE);// 字体样式
            WritableCellFormat wcf = new WritableCellFormat(font);
            // 背景色
            wcf.setBackground(jxl.format.Colour.BLUE_GREY);
            //水平居中对齐
            wcf.setAlignment(jxl.format.Alignment.CENTRE);
            //竖直方向居中对齐
            wcf.setVerticalAlignment(jxl.format.VerticalAlignment.CENTRE);
            //边框
            wcf.setBorder(jxl.format.Border.ALL, jxl.format.BorderLineStyle.THIN, jxl.format.Colour.WHITE);
            Label label = new Label(colIndex, rowIndex, dataFiled.getName(), wcf);
            sheet.setColumnView(colIndex, dataFiled.getColumnWidth());
            sheet.addCell(label);
            dataFiled.currentCol = colIndex;
            sheet.mergeCells(colIndex, rowIndex, colIndex + dataFiled.getColspan() - 1, rowIndex + dataFiled.getRowspan() - 1);
            colIndex = colIndex + dataFiled.getColspan(); //下一次列开始的地方
            //但是要考虑到下一行第一列被合并单元格占用了的情况。
            if (colIndex >= maxCol) {
                rowIndex++; //从下一行重新排列
                colIndex = 0; //默认从下一行的第一列开始排
            }
            while (isContains(rowIndex, colIndex, sheet)) {
                colIndex++; //如果该单元格已被占用，则向后移一格
                if (colIndex >= maxCol) {
                    rowIndex++; //从下一行重新排列
                    colIndex = 0; //默认从下一行的第一列开始排
                }
            }
        }
        return maxRow;
    }


    // 判断(rowIndex,colIndex)是否在合并的范围之内
    public boolean isContains(int rowIndex, int colIndex, WritableSheet sheet) {
        Range[] rangeCell = sheet.getMergedCells();
        for (int i = 0; i < rangeCell.length; i++) {
            int leftRow = rangeCell[i].getTopLeft().getRow();
            int leftCol = rangeCell[i].getTopLeft().getColumn();
            int rightRow = rangeCell[i].getBottomRight().getRow();
            int rightCol = rangeCell[i].getBottomRight().getColumn();
            if (leftRow <= rowIndex && rowIndex <= rightRow && leftCol <= colIndex && colIndex <= rightCol) {
                return true;
            }
        }
        return false;
    }


    private String createSheetName(int index) {
        if (sheetName == null) {
            this.sheetName = "sheet";
        }
        return this.sheetName + index;
    }

    public void setSheetName(String sheetName) {
        this.sheetName = sheetName;
    }
}
